/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2007 OPeNDAP, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
/////////////////////////////////////////////////////////////////////////////
using System;
using System.IO;
using NDODS.DAP.BaseTypes;
using NDODS.DAP.Parser;

namespace NDODS.DAP.Server
{
    /// <summary> Holds a OPeNDAP Server <code>Unsigned Int32</code> value.
    /// 
    /// </summary>
    /// <author>  ndp
    /// </author>
    /// <version>  $Revision: 15901 $
    /// </version>
    /// <seealso cref="BaseType">
    /// </seealso>
    [Serializable]
    public abstract class SDUInt32 : DUInt32, IServerMethods, IRelOps, ExprParserConstants
    {
        //UPGRADE_NOTE: Respective javadoc comments were merged.  It should be changed in order to comply with .NET documentation conventions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1199'"
        /// <summary> Get the value of the IsRead property.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if the variable has been Read,
        /// <code>false</code> otherwise.
        /// </returns>
        /// <seealso cref="Read">
        /// </seealso>

        /// <summary> Set the IsRead property. A normal variable is Read using the
        /// <code>Read()</code> method. Once Read the <em>IsRead</em> property is
        /// <code>true</code>. Use this function to manually set the property
        /// value. By default this property is false.
        /// 
        /// </summary>
        /// <seealso cref="Read">
        /// </seealso>
        public virtual bool IsRead {
            get { return (ReadMe); }

            set { ReadMe = value; }
        }

        private bool Project;
        private bool Synthesized;
        private bool ReadMe;

        /// <summary> Constructs a new <code>SDUInt32</code>.</summary>
        public SDUInt32() : base() {
            Project = false;
            Synthesized = false;
            ReadMe = false;
        }

        /// <summary> Constructs a new <code>SDUInt32</code> with name <code>n</code>.
        /// 
        /// </summary>
        /// <param name="n">the name of the variable.
        /// </param>
        public SDUInt32(String n) : base(n) {
            Project = false;
            Synthesized = false;
            ReadMe = false;
        }


        /// <summary> Write the variable's declaration in a C-style syntax. This
        /// function is used to create textual representation of the Data
        /// Descriptor Structure (DDS).  See <em>The OPeNDAP User Manual</em> for
        /// information about this structure.
        /// 
        /// </summary>
        /// <param name="os">         The <code>StreamWriter</code> on which to Print the
        /// declaration.
        /// </param>
        /// <param name="space">      Each line of the declaration will begin with the
        /// characters in this string.  Usually used for leading spaces.
        /// </param>
        /// <param name="Print_semi"> a bool value indicating whether to Print a
        /// semicolon at the end of the declaration.
        /// </param>
        /// <param name="constrained">a bool value indicating whether to Print
        /// the declartion dependent on the projection information. <b>This
        /// is only used by Server side code.</b>
        /// </param>
        /// <seealso cref="DDS">
        /// </seealso>
        public override void PrintDeclaration(StreamWriter os, String space, bool print_semi, bool constrained) {
            if (constrained && !Project)
                return;

            // BEWARE! Since PrintDeclaration()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintDeclaration() in BaseType
            // lead to one signature, we must be careful to override that
            // SAME signature here. That way all calls to PrintDeclaration() for
            // this object lead to this implementation.

            // Also, since PrintDeclaration()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintDeclaration() in BaseType
            // lead to the signature we are overriding here, we MUST call
            // the PrintDeclaration with the SAME signature THROUGH the super class
            // reference (assuming we want the super class functionality). If
            // we do otherwise, we will create an infinte call loop. OOPS!

            base.PrintDeclaration(os, space, print_semi, constrained);
        }


        /// <summary> Prints the value of the variable, with its declaration.  This
        /// function is primarily intended for debugging OPeNDAP applications and
        /// text-based clients such as geturl.
        /// <p/>
        /// <h2> Important Note</h2>
        /// This method overrides the BaseType method of the same name and
        /// type signature and it significantly changes the behavior for all versions
        /// of <code>PrintValue()</code> for this type:
        /// <b><i> All the various versions of printVal() will only
        /// Print a value, or a value with declaration, if the variable is
        /// in the projection.</i></b>
        /// <br>
        /// <br>In other words, if a call to
        /// <code>isProject()</code> for a particular variable returns
        /// <code>true</code> then <code>printVal()</code> will Print a value
        /// (or a declaration and a value).
        /// <br>
        /// <br>If <code>isProject()</code> for a particular variable returns
        /// <code>false</code> then <code>printVal()</code> is basically a No-Op.
        /// <br>
        /// <br>
        /// 
        /// </summary>
        /// <param name="os">          the <code>StreamWriter</code> on which to Print the value.
        /// </param>
        /// <param name="space">       this value is passed to the <code>PrintDeclaration</code> method,
        /// and controls the leading spaces of the output.
        /// </param>
        /// <param name="Print_decl_p">a bool value controlling whether the
        /// variable declaration is printed as well as the value.
        /// </param>
        /// <seealso cref="BaseType.PrintValue(StreamWriter,string,bool)">
        /// </seealso>
        /// <seealso cref="ServerMethods.isProject()">
        /// </seealso>
        public override void PrintValue(StreamWriter os, String space, bool print_decl_p) {
            if (!Project)
                return;
            base.PrintValue(os, space, print_decl_p);
        }

        // --------------- Projection Interface

        /// <summary> Set the state of this variable's projection. <code>true</code> means
        /// that this variable is part of the current projection as defined by
        /// the current constraint expression, otherwise the current projection
        /// for this variable should be <code>false</code>.
        /// 
        /// </summary>
        /// <param name="state"><code>true</code> if the variable is part of the current
        /// projection, <code>false</code> otherwise.
        /// </param>
        /// <param name="all">  This parameter has no effect for this type of variable.
        /// </param>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        public virtual void setProject(bool state, bool all) {
            Project = state;
        }

        /// <summary> Set the state of this variable's projection. <code>true</code> means
        /// that this variable is part of the current projection as defined by
        /// the current constraint expression, otherwise the current projection
        /// for this variable should be <code>false</code>.
        /// 
        /// </summary>
        /// <param name="state"><code>true</code> if the variable is part of the current
        /// projection, <code>false</code> otherwise.
        /// </param>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        public virtual void setProject(bool state) {
            setProject(state, true);
        }

        /// <summary> Check the projection state of this variable.
        /// Is the given variable marked as projected? If the variable is listed
        /// in the projection part of a constraint expression, then the CE parser
        /// should mark it as <em>projected</em>. When this method is called on
        /// such a variable it should return <code>true</code>, otherwise it
        /// should return <code>false</code>.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if the variable is part of the current
        /// projections, <code>false</code> otherwise.
        /// </returns>
        /// <seealso cref="CEEvaluator">
        /// </seealso>
        /// <seealso cref="setProject(bool)">
        /// </seealso>
        public virtual bool isProject() {
            return (Project);
        }

        // --------------- RelOps Interface

        /// <summary> The RelOps interface defines how each type responds to relational
        /// operators. Most (all?) types will not have sensible responses to all of
        /// the relational operators (e.g. DInt won't know how to match a regular
        /// expression but DString will). For those operators that are nonsensical a
        /// class should throw InvalidOperatorException.
        /// </summary>
        public virtual bool equal(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.EQUAL, this, bt));
        }

        public virtual bool not_equal(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.NOT_EQUAL, this, bt));
        }

        public virtual bool greater(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.GREATER, this, bt));
        }

        public virtual bool greater_eql(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.GREATER_EQL, this, bt));
        }

        public virtual bool less(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.LESS, this, bt));
        }

        public virtual bool less_eql(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.LESS_EQL, this, bt));
        }

        public virtual bool regexp(BaseType bt) {
            return (Operator.op(ExprParserConstants_Fields.REGEXP, this, bt));
        }

        // --------------- FileIO Interface

        /// <summary> Set the Synthesized property.
        /// 
        /// </summary>
        /// <param name="state">If <code>true</code> then the variable is considered a
        /// synthetic variable and no part of OPeNDAP will ever try to Read it from a
        /// file, otherwise if <code>false</code> the variable is considered a
        /// normal variable whose value should be Read using the
        /// <code>Read()</code> method. By default this property is false.
        /// </param>
        /// <seealso cref="IsSynthesized">
        /// </seealso>
        /// <seealso cref="Read">
        /// </seealso>
        public virtual void setSynthesized(bool state) {
            Synthesized = state;
        }

        /// <summary> Get the value of the Synthesized property.
        /// 
        /// </summary>
        /// <returns> <code>true</code> if this is a synthetic variable,
        /// <code>false</code> otherwise.
        /// </returns>
        public virtual bool IsSynthesized() {
            return (Synthesized);
        }

        /// <summary> IsRead a value from the named dataset for this variable.
        /// 
        /// </summary>
        /// <param name="datasetName">String identifying the file or other data store
        /// from which to Read a vaue for this variable.
        /// </param>
        /// <param name="specialO">   This <code>Object</code> is a goody that is used by Server implementations
        /// to deliver important, and as yet unknown, stuff to the Read method. If you
        /// don't need it, make it a <code>null</code>.
        /// </param>
        /// <returns> <code>true</code> if more data remains to be Read, otherwise
        /// <code>false</code>. This is an abtsract method that must be implemented
        /// as part of the installation/localization of a OPeNDAP server.
        /// </returns>
        /// <throws>  IOException </throws>
        /// <throws>  EOFException </throws>
        public abstract bool Read(String datasetName, Object specialO);


        /// <summary> Server-side serialization for OPeNDAP variables (sub-classes of
        /// <code>BaseType</code>).
        /// This does not send the entire class as the Java <code>Serializable</code>
        /// interface does, rather it sends only the binary data values. Other software
        /// is responsible for sending variable type information (see <code>DDS</code>).
        /// <p/>
        /// Writes data to a <code>DataOutputStream</code>. This method is used
        /// on the server side of the OPeNDAP client/server connection, and possibly
        /// by GUI clients which need to download OPeNDAP data, manipulate it, and
        /// then re-save it as a binary file.
        /// 
        /// </summary>
        /// <param name="sink">a <code>DataOutputStream</code> to write to.
        /// </param>
        /// <throws>  IOException thrown on any <code>OutputStream</code> exception. </throws>
        /// <seealso cref="BaseType">
        /// </seealso>
        /// <seealso cref="DDS">
        /// </seealso>
        /// <seealso cref="ServerDDS">
        /// </seealso>
        //UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
        public virtual void serialize(String dataset, BinaryWriter sink, CEEvaluator ce, Object specialO) {
            if (!IsRead)
                Read(dataset, specialO);

            if (ce.evalClauses(specialO))
                Externalize(sink);
        }

        /// <summary> Write the variable's declaration in XML. This
        /// function is used to create the XML representation of the Data
        /// Descriptor Structure (DDS).  See <em>The OPeNDAP User Manual</em> for
        /// information about this structure.
        /// 
        /// </summary>
        /// <param name="constrained">a bool value indicating whether to Print
        /// the declartion dependent on the projection information. <b>This
        /// is only used by Server side code.</b>
        /// </param>
        /// <seealso cref="DDS">
        /// </seealso>
        public override void PrintXML(StreamWriter pw, String pad, bool constrained) {
            if (constrained && !Project)
                return;

            // BEWARE! Since PrintXML()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintXML() in BaseType
            // lead to one signature, we must be careful to override that
            // SAME signature here. That way all calls to PrintDeclaration() for
            // this object lead to this implementation.

            // Also, since PrintXML()is (multiple) overloaded in BaseType
            // and all of the different signatures of PrintXML() in BaseType
            // lead to the signature we are overriding here, we MUST call
            // the PrintXML with the SAME signature THROUGH the super class
            // reference (assuming we want the super class functionality). If
            // we do otherwise, we will create an infinte call loop. OOPS!

            base.PrintXML(pw, pad, constrained);
        }
    }
}